/*
 *  author: Honrun
 */
#include "stm32f4xx_hal.h"
#include "stdio.h"
#include "DevicesIIC.h"
#include "DevicesSoftIIC.h"
#include "DevicesRT8092.h"



static RT8092InfoType st_typeRT8092Info = {0};


static int8_t cRT8092ModSet(uint32_t uiChannel, uint32_t uiMode);
static void vRT8092GetBank(float fVoltageValue, uint8_t ucBankOld, uint8_t *pucRegValue, uint8_t *pucRegBank);


void vRT8092Init(void)
{
    vIIC1Init();
    vIIC2Init();
    vIIC3Init();
    vSoftIICRT8092VCC2Init();

    cRT8092ModSet(RT8092_CHANNEL_ALL, RT8092_VOUT_MODE_PWM);
}

int8_t cRT8092ValueSet(uint32_t uiChannel, float fValue)
{
    uint8_t ucValue = 0, ucRegBank = 0;
    int8_t cError = 0;

    if(uiChannel & RT8092_CHANNEL_VDD1)
    {
        /* 当指数寄存器有变化时，才进行修改 */
        vRT8092GetBank(fValue, st_typeRT8092Info.vdd1.regBank, &ucValue, &ucRegBank);
        if(st_typeRT8092Info.vdd1.regBank != ucRegBank)
        {
            st_typeRT8092Info.vdd1.regBank = ucRegBank;
            cError |= cIIC1WriteByte(RT8092_IIC_ADDR, RT8092_VOUT_BANK1_ADDR, ucRegBank);
            cError |= cIIC1WriteByte(RT8092_IIC_ADDR, RT8092_VOUT_SEL1_ADDR, ucValue);
        }
        /* 最高位为软件开关控制，设置Bank时，需要置0 */
        ucValue |= 0x80;
        cError |= cIIC1WriteByte(RT8092_IIC_ADDR, RT8092_VOUT_SEL1_ADDR, ucValue);

        if(cError != 0)
        {
            printfError("VCC1 RT8092 IIC error.\r\n");
        }

        st_typeRT8092Info.vdd1.voltageSet = fValue;
    }

    if(uiChannel & RT8092_CHANNEL_VDD2H)
    {
        /* 当指数寄存器有变化时，才进行修改 */
        vRT8092GetBank(fValue, st_typeRT8092Info.vdd2H.regBank, &ucValue, &ucRegBank);
        if(st_typeRT8092Info.vdd2H.regBank != ucRegBank)
        {
            st_typeRT8092Info.vdd2H.regBank = ucRegBank;
            cError |= cIIC2WriteByte(RT8092_IIC_ADDR, RT8092_VOUT_BANK1_ADDR, ucRegBank);
            cError |= cIIC2WriteByte(RT8092_IIC_ADDR, RT8092_VOUT_SEL1_ADDR, ucValue);
        }
        /* 最高位为软件开关控制，设置Bank时，需要置0 */
        ucValue |= 0x80;
        cError |= cIIC2WriteByte(RT8092_IIC_ADDR, RT8092_VOUT_SEL1_ADDR, ucValue);

        if(cError != 0)
        {
            printfError("VCC2H RT8092 IIC error.\r\n");
        }

        st_typeRT8092Info.vdd2H.voltageSet = fValue;
    }

    if(uiChannel & RT8092_CHANNEL_VDD2L)
    {
        /* 当指数寄存器有变化时，才进行修改 */
        vRT8092GetBank(fValue, st_typeRT8092Info.vdd2L.regBank, &ucValue, &ucRegBank);
        if(st_typeRT8092Info.vdd2L.regBank != ucRegBank)
        {
            st_typeRT8092Info.vdd2L.regBank = ucRegBank;
            cError |= cSoftIICRT8092VCC2WriteByte(RT8092_IIC_ADDR, RT8092_VOUT_BANK1_ADDR, ucRegBank);
            cError |= cSoftIICRT8092VCC2WriteByte(RT8092_IIC_ADDR, RT8092_VOUT_SEL1_ADDR, ucValue);
        }
        /* 最高位为软件开关控制，设置Bank时，需要置0 */
        ucValue |= 0x80;
        cError |= cSoftIICRT8092VCC2WriteByte(RT8092_IIC_ADDR, RT8092_VOUT_SEL1_ADDR, ucValue);

        if(cError != 0)
        {
            printfError("VCC2L RT8092 IIC error.\r\n");
        }

        st_typeRT8092Info.vdd2L.voltageSet = fValue;
    }

    if(uiChannel & RT8092_CHANNEL_VDDQ)
    {
        /* 当指数寄存器有变化时，才进行修改 */
        vRT8092GetBank(fValue, st_typeRT8092Info.vddQ.regBank, &ucValue, &ucRegBank);
        if(st_typeRT8092Info.vddQ.regBank != ucRegBank)
        {
            st_typeRT8092Info.vddQ.regBank = ucRegBank;
            cError |= cIIC3WriteByte(RT8092_IIC_ADDR, RT8092_VOUT_BANK1_ADDR, ucRegBank);
            cError |= cIIC3WriteByte(RT8092_IIC_ADDR, RT8092_VOUT_SEL1_ADDR, ucValue);
        }
        /* 最高位为软件开关控制，设置Bank时，需要置0 */
        ucValue |= 0x80;
        cError |= cIIC3WriteByte(RT8092_IIC_ADDR, RT8092_VOUT_SEL1_ADDR, ucValue);

        if(cError != 0)
        {
            printfError("VCCQ RT8092 IIC error.\r\n");
        }

        st_typeRT8092Info.vddQ.voltageSet = fValue;
    }

    return cError;
}

static int8_t cRT8092ModSet(uint32_t uiChannel, uint32_t uiMode)
{
    uint8_t ucControlRegRead = 0, ucControlRegWrite = uiMode, ucDischargeReg = 0xFF, ucIpeakReg = RT8092_IPEAK_4_7A, i = 0;
    int8_t cError = 0;

    if(uiChannel & RT8092_CHANNEL_VDD1)
    {
        cError |= cIIC1WriteByte(RT8092_IIC_ADDR, RT8092_DISCHARGE_ADDR, ucDischargeReg);
        cError |= cIIC1WriteByte(RT8092_IIC_ADDR, RT8092_IPEAK_ADDR, ucIpeakReg);
        /* 设置电源IC的模式（PWM、PFM） */
        ucControlRegRead = ~ucControlRegWrite;
        i = 10;
        while((ucControlRegRead != ucControlRegWrite) && (i--))
        {
            cError |= cIIC1WriteByte(RT8092_IIC_ADDR, RT8092_VOUT_MODE_ADDR, ucControlRegWrite);
            cError |= cIIC1ReadByte(RT8092_IIC_ADDR, RT8092_VOUT_MODE_ADDR, &ucControlRegRead);
        }
    }

    if(uiChannel & RT8092_CHANNEL_VDD2H)
    {
        cError |= cIIC2WriteByte(RT8092_IIC_ADDR, RT8092_DISCHARGE_ADDR, ucDischargeReg);
        cError |= cIIC2WriteByte(RT8092_IIC_ADDR, RT8092_IPEAK_ADDR, ucIpeakReg);
        /* 设置电源IC的模式（PWM、PFM） */
        ucControlRegRead = ~ucControlRegWrite;
        i = 10;
        while((ucControlRegRead != ucControlRegWrite) && (i--))
        {
            cError |= cIIC2WriteByte(RT8092_IIC_ADDR, RT8092_VOUT_MODE_ADDR, ucControlRegWrite);
            cError |= cIIC2ReadByte(RT8092_IIC_ADDR, RT8092_VOUT_MODE_ADDR, &ucControlRegRead);
        }
    }

    if(uiChannel & RT8092_CHANNEL_VDD2L)
    {
        cError |= cSoftIICRT8092VCC2WriteByte(RT8092_IIC_ADDR, RT8092_DISCHARGE_ADDR, ucDischargeReg);
        cError |= cSoftIICRT8092VCC2WriteByte(RT8092_IIC_ADDR, RT8092_IPEAK_ADDR, ucIpeakReg);
        /* 设置电源IC的模式（PWM、PFM） */
        ucControlRegRead = ~ucControlRegWrite;
        i = 10;
        while((ucControlRegRead != ucControlRegWrite) && (i--))
        {
            cError |= cSoftIICRT8092VCC2WriteByte(RT8092_IIC_ADDR, RT8092_VOUT_MODE_ADDR, ucControlRegWrite);
            cError |= cSoftIICRT8092VCC2ReadByte(RT8092_IIC_ADDR, RT8092_VOUT_MODE_ADDR, &ucControlRegRead);
        }
    }

    if(uiChannel & RT8092_CHANNEL_VDDQ)
    {
        cError |= cIIC3WriteByte(RT8092_IIC_ADDR, RT8092_DISCHARGE_ADDR, ucDischargeReg);
        cError |= cIIC3WriteByte(RT8092_IIC_ADDR, RT8092_IPEAK_ADDR, ucIpeakReg);
        /* 设置电源IC的模式（PWM、PFM） */
        ucControlRegRead = ~ucControlRegWrite;
        i = 10;
        while((ucControlRegRead != ucControlRegWrite) && (i--))
        {
            cError |= cIIC3WriteByte(RT8092_IIC_ADDR, RT8092_VOUT_MODE_ADDR, ucControlRegWrite);
            cError |= cIIC3ReadByte(RT8092_IIC_ADDR, RT8092_VOUT_MODE_ADDR, &ucControlRegRead);
        }
    }

    return cError;
}

static void vRT8092GetBank(float fVoltageValue, uint8_t ucBankOld, uint8_t *pucRegValue, uint8_t *pucRegBank)
{
    uint8_t cRegValue = 4;

    /* 判断是否需要切换Bank */
    switch(ucBankOld)
    {
        case 0: if( fVoltageValue < 700.00f)                               cRegValue = 0; break;
        case 1: if((fVoltageValue > 606.25f) && (fVoltageValue < 1400.0f)) cRegValue = 1; break;
        case 2: if((fVoltageValue > 1212.5f) && (fVoltageValue < 2800.0f)) cRegValue = 2; break;
        case 3: if( fVoltageValue > 2425.0f)                               cRegValue = 3; break;

        default:;
    }

    /* 计算Bank */
    if(cRegValue == 4)
    {
        if(fVoltageValue < 700.0f)       cRegValue = 0;
        else if(fVoltageValue < 1400.0f) cRegValue = 1;
        else if(fVoltageValue < 2800.0f) cRegValue = 2;
        else                             cRegValue = 3;

//        if(fVoltageValue > 2425.0f)      cRegValue = 3;
//        else if(fVoltageValue > 1212.5f) cRegValue = 2;
//        else if(fVoltageValue > 606.25f) cRegValue = 1;
//        else                             cRegValue = 0;
    }

    switch(cRegValue)
    {
        case 0: *pucRegValue = (uint8_t)((fVoltageValue - 303.125f) * 0.32f); break;
        case 1: *pucRegValue = (uint8_t)((fVoltageValue * 0.5f - 303.125f) * 0.32f); break;
        case 2: *pucRegValue = (uint8_t)((fVoltageValue * 0.25f - 303.125f) * 0.32f); break;
        case 3: *pucRegValue = (uint8_t)((fVoltageValue * 0.125f - 303.125f) * 0.32f); break;

        default: break;
    }

    *pucRegValue &= 0x7F;
    *pucRegBank = cRegValue;
}

/* 各 Bank 的分辨率 */
 float fRT8092GetErrorValue(uint8_t ucBank)
{
    float fValue = 25.0f;

    if(ucBank == 0)
        fValue = 3.125f;
    else if(ucBank == 1)
        fValue = 6.25f;
    else if(ucBank == 2)
        fValue = 12.5f;

    return fValue;
}

RT8092InfoType *ptypeRT8092InfoGet(void)
{
    return &st_typeRT8092Info;
}
